#include "TSS_Task.h"

TSS_TaskList TSS_TASKLIST = {
    .TASK_Count = 1,
};

/**
  * @brief  TSS操作系统初始化
  * @retval 无
  * @note   会自动开启systick中断
  */
void TSS_Init(void)
{
#ifdef STM32F10x
    SysTick_Config(SystemCoreClock / TSS_SYSHZ - 1);
#endif
#ifdef STM32F4xx
    SysTick_Config(SystemCoreClock / TSS_SYSHZ - 1);
#endif
}

/**
  * @brief  系统中断服务函数
  * @retval 无
  * @note   需在systick中断中调用
  */
const int32_t tickinc = 1000 / TSS_SYSHZ;
void TSS_SystickHandler(void)
{
    uint8_t i;
    TSS_TASKLIST.TSS_RunTime += tickinc;
    //检索一遍任务
    for (i = 1; i < TSS_TASKLIST.TASK_Count; i++)
    {
        TSS_TASKLIST.TASK_List[i].Delay[DELAY_TICK] -= tickinc;
        //如果任务计时到达
        if (TSS_TASKLIST.TASK_List[i].Delay[DELAY_TICK] <= 0)
        {
            TSS_TASKLIST.TASK_List[i].Delay[DELAY_TICK] = TSS_TASKLIST.TASK_List[i].Delay[DELAY_CYCLE];
            TSS_TASKLIST.TASK_List[i].Status = TASK_Ready;
        }
    }
}

/**
  * @brief  系统空闲任务
  * @param  *p    传参待定
  * @retval 无
  * @note   用户可自行在代码中再次定义本任务
            TSS_IDLETASK = 1 本任务才有效
  */
__attribute__((weak)) void TSS_IdleTask(void *p)
{
}

/**
  * @brief  系统延时函数
  * @param  ms    需要延时的毫秒数
  * @retval 无
  * @note   精确到ms
  */
void TSS_Delay(uint32_t ms)
{
    uint32_t tickstart = TSS_TASKLIST.TSS_RunTime;
    uint32_t wait = ms;

    /* Add a period to guarantee minimum wait */
    if (wait < TSS_MAX_DELAY)
    {
        wait++;
    }
    while ((TSS_TASKLIST.TSS_RunTime - tickstart) < wait)
    {
    }
}

/**
  * @brief  获取系统运行毫秒数
  * @retval 运行ms
  * @note   精确到ms
  */
uint32_t TSS_GetRunTime(void)
{
    return TSS_TASKLIST.TSS_RunTime;
}

/**
  * @brief  创建一个任务
  * @param  Callback      任务函数名
  * @param  priority      优先级
  * @param  Types         任务类型
  * @param  Delay         任务运行周期
  * @retval 返回任务ID
  * @note   无
  */
uint8_t TSS_ThreadCreate(TSS_TaskFunction Callback, uint8_t Priority, TSS_TaskTypes Types, int32_t Delay)
{
    if (TSS_TASKLIST.TASK_Count >= TSS_TASKNUMMAX)
        return TSS_ERROR;

    uint8_t last_Count = TSS_TASKLIST.TASK_Count;
    switch (Types)
    {
    case TASK_HZ:
        TSS_TASKLIST.TASK_List[last_Count].ID = TSS_TASKLIST.TASK_Count;
        TSS_TASKLIST.TASK_List[last_Count].Priority = Priority;
        TSS_TASKLIST.TASK_List[last_Count].Delay[DELAY_TICK] = Delay;
        TSS_TASKLIST.TASK_List[last_Count].Delay[DELAY_CYCLE] = Delay;
        TSS_TASKLIST.TASK_List[last_Count].Callback = Callback;
        TSS_TASKLIST.TASK_List[last_Count].Status = TASK_Ready;
        TSS_TASKLIST.TASK_List[last_Count].Types = Types;
        break;
    case TASK_TRIGGER:
        TSS_TASKLIST.TASK_List[last_Count].ID = TSS_TASKLIST.TASK_Count;
        TSS_TASKLIST.TASK_List[last_Count].Priority = Priority;
        TSS_TASKLIST.TASK_List[last_Count].Delay[DELAY_TICK] = TSS_MAX_DELAY;
        TSS_TASKLIST.TASK_List[last_Count].Delay[DELAY_CYCLE] = TSS_MAX_DELAY;
        TSS_TASKLIST.TASK_List[last_Count].Callback = Callback;
        TSS_TASKLIST.TASK_List[last_Count].Status = TASK_Blocked;
        TSS_TASKLIST.TASK_List[last_Count].Types = Types;
        break;
    default:
        break;
    }

    TSS_TASKLIST.TASK_Count++;

    return last_Count;
}

/**
  * @brief  修改一个任务的运行周期
  * @param  ThreadID    任务ID
  * @param  Delay         任务运行周期
  * @retval 无
  * @note   只有周期任务才能修改运行周期
  */
void TSS_ThreadDelayChange(uint8_t ThreadID, int32_t Delay)
{
    if (TSS_TASKLIST.TASK_List[ThreadID].Types == TASK_HZ)
    {
        TSS_TASKLIST.TASK_List[ThreadID].Delay[DELAY_TICK] = Delay;
        TSS_TASKLIST.TASK_List[ThreadID].Delay[DELAY_CYCLE] = Delay;
    }
    else if (TSS_TASKLIST.TASK_List[ThreadID].Types == TASK_TRIGGER)
    {
        TSS_TASKLIST.TASK_List[TSS_TASKLIST.TASK_Count].Delay[DELAY_TICK] = TSS_MAX_DELAY;
        TSS_TASKLIST.TASK_List[TSS_TASKLIST.TASK_Count].Delay[DELAY_CYCLE] = TSS_MAX_DELAY;
    }
}

/**
  * @brief  触发一个异步任务的执行
  * @param  ThreadID    任务ID
  * @param  Delay       0，任务立刻执行；>0，延时一定时间执行
  * @retval 无
  * @note   需要立刻执行的任务会以最快的速度得到执行
            不是立刻执行的任务会被刷新执行时间
  */
void TSS_ThreadSetTrigger(uint8_t ThreadID, int32_t Delay)
{
    if (TSS_TASKLIST.TASK_List[ThreadID].Types == TASK_TRIGGER)
    {
        //如果是一个需要立刻执行的任务
        if (Delay <= 0)
        {
#if TSS_TRIGGERNOW == 1 //这种触发方式实时性较好，但是在中断中调用会影响实时性
            TSS_TASKLIST.TASK_List[ThreadID].Delay[DELAY_TICK] = TSS_TASKLIST.TASK_List[ThreadID].Delay[DELAY_CYCLE];
            TSS_TASKLIST.TASK_List[ThreadID].Status = TASK_Running;
            TSS_TASKLIST.TASK_List[ThreadID].Callback(NULL);
#else //这种方式实时性一般，但是依然能保证任务得到执行
            TSS_TASKLIST.TASK_List[ThreadID].Status = TASK_Ready;
            TSS_TASKLIST.TASK_List[ThreadID].Delay[DELAY_TICK] = 0;
#endif
        }
        else
        {
            TSS_TASKLIST.TASK_List[ThreadID].Delay[DELAY_TICK] = Delay;
        }
    }
}

/**
  * @brief  向一个任务发送message
  * @param  ThreadID    任务ID
  * @param  message     消息
  * @retval 无
  * @note   本消息发出即赋值
  */
void TSS_ThreadPutMessage(uint8_t ThreadID, TSS_TaskMessageDef message)
{
    TSS_TASKLIST.TASK_List[ThreadID].Message = message;
    TSS_TASKLIST.TASK_List[ThreadID].Message.effect = 1;
}

/**
  * @brief  启动时间片轮训操作系统
  * @retval 无
  * @note   无
  */
void TSS_Start(void)
{
    uint8_t i;
    TSS_TaskInfoDef *ReadyTask = NULL;
    while (1)
    {
        ReadyTask = &TSS_TASKLIST.TASK_List[0];
        //检索一遍任务
        for (i = 1; i < TSS_TASKLIST.TASK_Count; i++)
        {
            //找到需要执行的任务
            if (TSS_TASKLIST.TASK_List[i].Status == TASK_Ready && TSS_TASKLIST.TASK_List[i].Priority >= ReadyTask->Priority)
            {
                //找出优先级最高的任务
                ReadyTask = &TSS_TASKLIST.TASK_List[i];
            }
        }
        //执行任务函数
        if (ReadyTask != &TSS_TASKLIST.TASK_List[0] && ReadyTask->Callback != NULL && ReadyTask->Status == TASK_Ready)
        {
            ReadyTask->Status = TASK_Running;
            ReadyTask->Message.past = ReadyTask->Delay[DELAY_CYCLE] - ReadyTask->Delay[DELAY_TICK];
            ReadyTask->Callback(&ReadyTask->Message);
            //任务结束处理
            ReadyTask->Message.effect = 0;
            ReadyTask->Status = TASK_Blocked;
        }
#if TSS_IDLETASK == 1
        //执行空闲任务
        else
        {
            TSS_IdleTask(NULL);
        }
#endif
    }
}
